package com.spsoft.vatoutinv.service.vmshzqrdmanage.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.leqidmz.param.ApplyRedConfirmDetailParam;
import com.spsoft.core.model.leqidmz.param.ConfirmRedConfirmParam;
import com.spsoft.core.model.leqidmz.param.QueryRedConfirmDetailParam;
import com.spsoft.core.model.leqidmz.response.ApplyRedConfirmVO;
import com.spsoft.core.model.leqidmz.response.ConfirmRedConfirmVO;
import com.spsoft.core.model.leqidmz.response.QueryRedConfirmDetailVO;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.SecurityUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.einvoicetodmz.service.DmzApiClientService;
import com.spsoft.system.entity.NvatOutInvoiceDetails;
import com.spsoft.system.entity.NvatOutInvoiceItems;
import com.spsoft.system.entity.NvatOutInvomapSelf;
import com.spsoft.system.entity.NvatTaxhardwarelunit;
import com.spsoft.system.mapper.NvatOutInvoiceDetailsMapper;
import com.spsoft.system.mapper.NvatOutInvoiceItemsMapper;
import com.spsoft.system.mapper.NvatOutInvomapselfMapper;
import com.spsoft.system.mapper.NvatTaxhardwarelunitMapper;
import com.spsoft.system.model.vo.DefBizdictVo;
import com.spsoft.system.model.vo.InvoiceItemVo;
import com.spsoft.system.model.vo.InvoiceVo;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.entity.vmsclassifycode.VmsClassifyCode;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.VmsFullOutInvoiceDetails;
import com.spsoft.vatoutinv.entity.vmshzqrdmanage.VmsApprovalHzqrd;
import com.spsoft.vatoutinv.entity.vmshzqrdmanage.VmsApprovalHzqrdItem;
import com.spsoft.vatoutinv.entity.vmshzqrdmanage.VmsLeqiHzqrd;
import com.spsoft.vatoutinv.entity.vmshzqrdmanage.VmsLeqiHzqrdItem;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.enums.HzqrdStatusEnum;
import com.spsoft.vatoutinv.model.dto.vmshzqrdmanage.*;
import com.spsoft.vatoutinv.model.vo.vmsfulloutinvoice.VmsFullOutInvoicePageVO;
import com.spsoft.vatoutinv.model.vo.vmshzqrdmanage.VmsApprovalHzqrdItemVo;
import com.spsoft.vatoutinv.model.vo.vmshzqrdmanage.VmsApprovalHzqrdSimpleVo;
import com.spsoft.vatoutinv.model.vo.vmshzqrdmanage.VmsApprovalHzqrdTotalSimpleVo;
import com.spsoft.vatoutinv.model.vo.vmshzqrdmanage.VmsApprovalHzqrdVo;
import com.spsoft.vatoutinv.service.commoninvoice.CommonInvoiceService;
import com.spsoft.vatoutinv.service.vmsclassifycode.VmsClassifyCodeService;
import com.spsoft.vatoutinv.service.vmsenterpriseinfo.VmsEnterpriseInfoService;
import com.spsoft.vatoutinv.service.vmsfulloutinvoice.VmsFullOutInvoiceDetailsService;
import com.spsoft.vatoutinv.service.vmshzqrdmanage.*;
import com.spsoft.workflow.common.enums.BizStatusEnums;
import com.spsoft.workflow.entity.WfProcessBusiness;
import com.spsoft.workflow.service.impl.ProcessBusinessServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 红字确认单申请 服务实现类
 *
 * @author : chenxudong
 * @date : 2024/1/4 17:14
 */
@Slf4j
@Service
@RequiredArgsConstructor
@SuppressWarnings("unchecked")
public class VmsHzqrdApplyServiceImpl implements VmsHzqrdApplyService {

    public static final String LOG_MSG = "(红字确认单申请实现层)";

    private final VmsApprovalHzqrdService vmsApprovalHzqrdService;

    private final VmsApprovalHzqrdItemService vmsApprovalHzqrdItemService;

    private final DmzApiClientService dmzApiClientService;

    private final VmsLeqiHzqrdService vmsLeqiHzqrdService;

    private final VmsLeqiHzqrdItemService vmsLeqiHzqrdItemService;

    private final VmsEnterpriseInfoService vmsEnterpriseInfoService;

    private final VmsFullOutInvoiceDetailsService vmsFullOutInvoiceDetailsService;

    private final VmsClassifyCodeService vmsClassifyCodeService;

    private final ProcessBusinessServiceImpl processBusinessService;

    private final NvatOutInvoiceDetailsMapper nvatOutInvoiceDetailsMapper;

    private final NvatOutInvoiceItemsMapper nvatOutInvoiceItemsMapper;

    private final NvatOutInvomapselfMapper nvatOutInvomapselfMapper;

    private final NvatTaxhardwarelunitMapper nvatTaxhardwarelunitMapper;

    private final CommonInvoiceService commonInvoiceService;

    @Override
    public Result<IPage<VmsApprovalHzqrdVo>> pageApply(VmsApprovalHzqrdPageDto pageDto) {
        // 分页查询
        Page<VmsApprovalHzqrd> page = new Page<>(pageDto.getPageNo(), pageDto.getPageSize());
        LambdaQueryWrapper<VmsApprovalHzqrd> wrapper = new LambdaQueryWrapper<>();

        // 查询审批流程类型为红字确认单申请的数据
        wrapper.eq(VmsApprovalHzqrd::getApplyType, CommonEnum.HZQRD_APPROVAL_TYPE_0.getKey());
        // 查询当前机构创建人是自己，或者审批人是自己的数据
        wrapper.eq(VmsApprovalHzqrd::getQydjid, pageDto.getDeptCode());
        wrapper.and(i -> i.eq(VmsApprovalHzqrd::getCreatBy, pageDto.getCreatBy())
                        .or()
                        .eq(VmsApprovalHzqrd::getApprovalBy, pageDto.getCreatBy()));
        // 查询未删除的数据
        wrapper.eq(VmsApprovalHzqrd::getDelFlag, CommonEnum.DEL_STATUS_0.getKey());
        wrapper.eq(StringUtil.isNotBlank(pageDto.getHzqrxxztdm()), VmsApprovalHzqrd::getHzqrxxztdm, pageDto.getHzqrxxztdm());
        wrapper.eq(StringUtil.isNotBlank(pageDto.getChyydm()), VmsApprovalHzqrd::getChyydm, pageDto.getChyydm());
        wrapper.likeRight(StringUtil.isNotBlank(pageDto.getLzfphm()), VmsApprovalHzqrd::getLzfphm, pageDto.getLzfphm());
        wrapper.likeRight(StringUtil.isNotBlank(pageDto.getHzfpxxqrdbh()), VmsApprovalHzqrd::getHzfpxxqrdbh, pageDto.getHzfpxxqrdbh());
        if (StringUtil.isNotBlank(pageDto.getLzfpkprqq()) && StringUtil.isNotBlank(pageDto.getLzfpkprqz())) {
            // 蓝字发票开票日期起止
            String lzfpkprqq = DateUtil.format(DateUtil.beginOfDay(DateUtil.parseDate(pageDto.getLzfpkprqq())), CommonConstant.DATE_FORMAT_14);
            String lzfpkprqz = DateUtil.format(DateUtil.endOfDay(DateUtil.parseDate(pageDto.getLzfpkprqz())), CommonConstant.DATE_FORMAT_14);
            wrapper.apply("LZKPRQ >= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", lzfpkprqq);
            wrapper.apply("LZKPRQ <= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", lzfpkprqz);
        }
        if (StringUtil.isNotBlank(pageDto.getHzqrdsqrqq()) && StringUtil.isNotBlank(pageDto.getHzqrdsqrqz())) {
            // 红字确认单申请日期起止
            String hzqrdsqrqq = DateUtil.format(DateUtil.beginOfDay(DateUtil.parseDate(pageDto.getHzqrdsqrqq())), CommonConstant.DATE_FORMAT_14);
            String hzqrdsqrqz = DateUtil.format(DateUtil.endOfDay(DateUtil.parseDate(pageDto.getHzqrdsqrqz())), CommonConstant.DATE_FORMAT_14);
            wrapper.apply("LRRQ >= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", hzqrdsqrqq);
            wrapper.apply("LRRQ <= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", hzqrdsqrqz);
        }
        wrapper.orderByDesc(VmsApprovalHzqrd::getCreatTime, VmsApprovalHzqrd::getId);

        Page<VmsApprovalHzqrd> IPage = vmsApprovalHzqrdService.page(page, wrapper);
        // 将数据库返回数据转换为VO返回前端
        IPage<VmsApprovalHzqrdVo> IPageVo = IPage.convert(item -> {
            VmsApprovalHzqrdVo vo = new VmsApprovalHzqrdVo();
            // 转换数据
            BeanUtils.copyBeanProp(vo, item);
            return vo;
        });

        return Result.OK(IPageVo);
    }

    @Override
    public Result<IPage<VmsFullOutInvoicePageVO>> pageInvoice(VmsHclzfpPageDto pageDto) {
        IPage<VmsFullOutInvoicePageVO> IPageVo;
        // 根据数据类型区分查询进项票还是销项票
        if (CommonEnum.SJLX_JX.getKey().equals(pageDto.getSjlx())) {
            log.info("{}红冲蓝字发票选择页面，数据来源：进项票", LOG_MSG);
            IPageVo = null;
        } else {
            log.info("{}红冲蓝字发票选择页面，数据来源：销项票", LOG_MSG);
            // 根据发票类型区分查询老增值税表还是新数电表
            if (StrUtil.equalsAny(pageDto.getFplx(), CommonEnum.INVOICE_TYPE_01.getKey(), CommonEnum.INVOICE_TYPE_02.getKey())) {
                // 数电发票查询
                log.info("{}红冲蓝字发票选择页面，数电发票查询", LOG_MSG);
                // 分页查询
                Page<VmsFullOutInvoiceDetails> page = new Page<>(pageDto.getPageNo(), pageDto.getPageSize());
                LambdaQueryWrapper<VmsFullOutInvoiceDetails> wrapper = new LambdaQueryWrapper<>();
                // 当前机构的蓝字发票
                wrapper.eq(VmsFullOutInvoiceDetails::getQydjid, SecurityUtils.getDeptCode());
                wrapper.eq(VmsFullOutInvoiceDetails::getLzfpbz, CommonEnum.INVOICE_BLUE.getKey());
                // 只有上传乐企成功的蓝字发票允许红冲
                wrapper.eq(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_2.getKey());
                wrapper.eq(StringUtil.isNotBlank(pageDto.getSjly()), VmsFullOutInvoiceDetails::getSjly, pageDto.getSjly());
                wrapper.eq(StringUtil.isNotBlank(pageDto.getFplx()), VmsFullOutInvoiceDetails::getFppz, pageDto.getFplx());
                if (StringUtil.isNotBlank(pageDto.getLzfpzt())) {
                    wrapper.eq(VmsFullOutInvoiceDetails::getFpzt, pageDto.getLzfpzt());
                } else {
                    wrapper.in(VmsFullOutInvoiceDetails::getFpzt, CommonEnum.INVOICE_STATUS_0.getKey(), CommonEnum.INVOICE_STATUS_7.getKey());
                }
                wrapper.likeRight(StringUtil.isNotBlank(pageDto.getGmfmc()), VmsFullOutInvoiceDetails::getGmfmc, pageDto.getGmfmc());
                wrapper.likeRight(StringUtil.isNotBlank(pageDto.getXsfmc()), VmsFullOutInvoiceDetails::getXsfmc, pageDto.getXsfmc());
                wrapper.likeRight(StringUtil.isNotBlank(pageDto.getLzfphm()), VmsFullOutInvoiceDetails::getFphm, pageDto.getLzfphm());
                if (StringUtil.isNotBlank(pageDto.getLzfpkprqq()) && StringUtil.isNotBlank(pageDto.getLzfpkprqz())) {
                    // 蓝字发票开票日期起止
                    String lzfpkprqq = DateUtil.format(DateUtil.beginOfDay(DateUtil.parseDate(pageDto.getLzfpkprqq())), CommonConstant.DATE_FORMAT_14);
                    String lzfpkprqz = DateUtil.format(DateUtil.endOfDay(DateUtil.parseDate(pageDto.getLzfpkprqz())), CommonConstant.DATE_FORMAT_14);
                    wrapper.apply("KPRQ >= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", lzfpkprqq);
                    wrapper.apply("KPRQ <= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", lzfpkprqz);
                }
                wrapper.orderByDesc(VmsFullOutInvoiceDetails::getKprq, VmsFullOutInvoiceDetails::getFoidid);

                Page<VmsFullOutInvoiceDetails> IPage = vmsFullOutInvoiceDetailsService.page(page, wrapper);
                // 将数据库返回数据转换为VO返回前端
                IPageVo = IPage.convert(item -> {
                    VmsFullOutInvoicePageVO vo = new VmsFullOutInvoicePageVO();
                    // 转换数据
                    BeanUtils.copyBeanProp(vo, item);
                    // 列表里前端取值蓝字发票号码
                    vo.setLzfphm(item.getFphm());
                    return vo;
                });
            } else {
                // 税控发票查询
                log.info("{}红冲蓝字发票选择页面，税控发票查询", LOG_MSG);
                // 分页查询
                Page<NvatOutInvoiceDetails> page = new Page<>(pageDto.getPageNo(), pageDto.getPageSize());
                LambdaQueryWrapper<NvatOutInvoiceDetails> wrapper = new LambdaQueryWrapper<>();
                // 当前机构的蓝字发票
                wrapper.eq(NvatOutInvoiceDetails::getQydjid, SecurityUtils.getDeptCode());
                wrapper.eq(NvatOutInvoiceDetails::getSffsfp, CommonEnum.INVOICE_BLUE.getKey());
                // 只有开票成功的蓝字发票允许红冲
                wrapper.eq(NvatOutInvoiceDetails::getKpzt, CommonEnum.KPZT_2.getKey());
                if (StringUtil.isNotBlank(pageDto.getSjly())) {
                    wrapper.eq(NvatOutInvoiceDetails::getSjly, Integer.parseInt(pageDto.getSjly()));
                }
                wrapper.eq(StringUtil.isNotBlank(pageDto.getFplx()), NvatOutInvoiceDetails::getFplxdm, pageDto.getFplx());
                // 发票状态：1正常，2作废，3冲红
                if (StringUtil.isNotBlank(pageDto.getLzfpzt())) {
                    wrapper.eq(NvatOutInvoiceDetails::getFpzt, pageDto.getLzfpzt());
                } else {
                    wrapper.in(NvatOutInvoiceDetails::getFpzt, CommonEnum.SK_INVOICE_STATUS_1.getKey(), CommonEnum.SK_INVOICE_STATUS_3.getKey());
                }
                wrapper.likeRight(StringUtil.isNotBlank(pageDto.getGmfmc()), NvatOutInvoiceDetails::getSpfmc, pageDto.getGmfmc());
                wrapper.likeRight(StringUtil.isNotBlank(pageDto.getXsfmc()), NvatOutInvoiceDetails::getKpdw, pageDto.getXsfmc());
                wrapper.likeRight(StringUtil.isNotBlank(pageDto.getLzfphm()), NvatOutInvoiceDetails::getFphm, pageDto.getLzfphm());
                if (StringUtil.isNotBlank(pageDto.getLzfpkprqq()) && StringUtil.isNotBlank(pageDto.getLzfpkprqz())) {
                    // 蓝字发票开票日期起止
                    String lzfpkprqq = DateUtil.format(DateUtil.beginOfDay(DateUtil.parseDate(pageDto.getLzfpkprqq())), CommonConstant.DATE_FORMAT_14);
                    String lzfpkprqz = DateUtil.format(DateUtil.endOfDay(DateUtil.parseDate(pageDto.getLzfpkprqz())), CommonConstant.DATE_FORMAT_14);
                    wrapper.apply("KPRQ >= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", lzfpkprqq);
                    wrapper.apply("KPRQ <= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", lzfpkprqz);
                }
                wrapper.orderByDesc(NvatOutInvoiceDetails::getKprq, NvatOutInvoiceDetails::getOidid);

                Page<NvatOutInvoiceDetails> IPage = nvatOutInvoiceDetailsMapper.selectPage(page, wrapper);
                // 将数据库返回数据转换为VO返回前端
                IPageVo = IPage.convert(item -> {
                    VmsFullOutInvoicePageVO vo = new VmsFullOutInvoicePageVO();
                    // 转换数据
                    BeanUtils.copyProperties(item, vo);
                    vo.setFppz(item.getFplxdm());
                    if (item.getFpzt() == 1) {
                        vo.setFpzt(CommonEnum.SK_INVOICE_STATUS_1.getValue());
                    } else {
                        vo.setFpzt(CommonEnum.SK_INVOICE_STATUS_3.getValue());
                    }
                    vo.setGmfmc(item.getSpfmc());
                    vo.setGmfnsrsbh(item.getSpfsbh());
                    vo.setBz(item.getKpbz());
                    vo.setSjly(StringUtil.toString(item.getSjly()));
                    // 列表里前端取值蓝字发票代码、蓝字发票号码
                    vo.setLzfpdm(item.getFpdm());
                    vo.setLzfphm(item.getFphm());
                    // 判断税控发票是否需要补全销售方信息
                    if (StringUtils.isBlank(item.getKpnsrsbh())) {
                        LambdaQueryWrapper<NvatTaxhardwarelunit> query = new LambdaQueryWrapper<>();
                        query.eq(NvatTaxhardwarelunit::getSbdwid, item.getSbdwid());
                        NvatTaxhardwarelunit info = nvatTaxhardwarelunitMapper.selectOne(query);
                        if (info != null) {
                            // 补全销售方名称、税号
                            vo.setXsfmc(info.getSbdwmc());
                            vo.setXsfnsrsbh(info.getNssbh());
                        }
                    } else {
                        vo.setXsfmc(item.getKpdw());
                        vo.setXsfnsrsbh(item.getKpnsrsbh());
                    }
                    return vo;
                });
            }
        }

        return Result.OK(IPageVo);
    }

    @Override
    public Result<VmsApprovalHzqrdTotalSimpleVo> fastAdd(String fpdm, String fphm, Long applyId) {
        // 调用乐企发票用途状态信息查询接口之前的校验
        if (StringUtils.isBlank(fphm)) {
            return Result.ERROR(ResponseEnum.LZFPHM_EMPTY_ERROR);
        }
        // 查询发票信息（可能是进项票、税控票、数电票）
        InvoiceVo invoiceVo = commonInvoiceService.queryInvoice(fpdm, fphm, true);
        if (invoiceVo == null) {
            return Result.ERROR(ResponseEnum.HZQRD_NO_INVOICE_ERROR);
        }

        if (!CommonEnum.INVOICE_BLUE.getKey().equals(invoiceVo.getLzfpbz())) {
            return Result.ERROR(ResponseEnum.HZQRD_APPLY_ERROR);
        }
        // 根据发票的数据库来源，进行校验
        if (CommonEnum.SJKLY_SD.getKey().equals(invoiceVo.getSjkly())) {
            // 校验数电蓝字发票乐企上传状态
            if (!CommonEnum.INVOICE_UPLOAD_STATUS_2.getKey().equals(invoiceVo.getSczt())) {
                String uploadStatus = "";
                if (CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey().equals(invoiceVo.getSczt())) {
                    uploadStatus = CommonEnum.INVOICE_UPLOAD_STATUS_0.getValue();
                } else if (CommonEnum.INVOICE_UPLOAD_STATUS_1.getKey().equals(invoiceVo.getSczt())) {
                    uploadStatus = CommonEnum.INVOICE_UPLOAD_STATUS_1.getValue();
                } else if (CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey().equals(invoiceVo.getSczt())) {
                    uploadStatus = CommonEnum.INVOICE_UPLOAD_STATUS_3.getValue();
                }
                return Result.ERRORT(ResponseEnum.BUSINESS_ERROR.getCode(), "选定的蓝字发票上传状态为" + uploadStatus + "！不允许发起红字确认单申请！");
            }
            // 现在接口未通，暂时使用本地的发票状态校验数电蓝字发票状态
            if (!StrUtil.equalsAny(invoiceVo.getSdfpzt(), CommonEnum.INVOICE_STATUS_0.getKey(), CommonEnum.INVOICE_STATUS_7.getKey())) {
                String invoiceStatus = "";
                if (CommonEnum.INVOICE_STATUS_2.getKey().equals(invoiceVo.getSdfpzt())) {
                    invoiceStatus = CommonEnum.INVOICE_STATUS_2.getValue();
                } else if (CommonEnum.INVOICE_STATUS_3.getKey().equals(invoiceVo.getSdfpzt())) {
                    invoiceStatus = CommonEnum.INVOICE_STATUS_3.getValue();
                } else if (CommonEnum.INVOICE_STATUS_8.getKey().equals(invoiceVo.getSdfpzt())) {
                    invoiceStatus = CommonEnum.INVOICE_STATUS_8.getValue();
                }
                return Result.ERRORT(ResponseEnum.BUSINESS_ERROR.getCode(), "选定的蓝字发票状态为" + invoiceStatus + "！不允许发起红字确认单申请！");
            }
        } else if (CommonEnum.SJKLY_SK.getKey().equals(invoiceVo.getSjkly())) {
            // 现在接口未通，暂时使用本地的发票状态校验税控蓝字发票状态
            if (CommonEnum.SK_INVOICE_STATUS_2.getKey().equals(invoiceVo.getSkfpzt())) {
                String invoiceStatus = CommonEnum.SK_INVOICE_STATUS_2.getValue();
                return Result.ERRORT(ResponseEnum.BUSINESS_ERROR.getCode(), "选定的蓝字发票状态为" + invoiceStatus + "！不允许发起红字确认单申请！");
            }
        }

        // 判断当前蓝字发票是否有在途的红字确认单申请流程，若存在则不允许再次提交红字确认单申请流程
        LambdaQueryWrapper<VmsApprovalHzqrd> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(fpdm)) {
            wrapper.eq(VmsApprovalHzqrd::getLzfpdm, fpdm);
        }
        wrapper.eq(VmsApprovalHzqrd::getLzfphm, fphm);
        wrapper.eq(VmsApprovalHzqrd::getApplyType, CommonEnum.HZQRD_APPROVAL_TYPE_0.getKey());
        wrapper.eq(VmsApprovalHzqrd::getDelFlag, CommonEnum.DEL_STATUS_0.getKey());
        List<VmsApprovalHzqrd> hzqrdList = vmsApprovalHzqrdService.list(wrapper);
        if (CollectionUtil.isNotEmpty(hzqrdList) && applyId != null) {
            // 保存未提交时，首页点击办理进入，删除本次未提交的流程
            hzqrdList.removeIf(vmsApprovalHzqrd -> applyId.equals(vmsApprovalHzqrd.getApplyId()));
        }
        if (CollectionUtil.isNotEmpty(hzqrdList)) {
            for (VmsApprovalHzqrd approvalHzqrd : hzqrdList) {
                LambdaQueryWrapper<WfProcessBusiness> query = new LambdaQueryWrapper<>();
                query.eq(WfProcessBusiness::getId, approvalHzqrd.getApplyId());
                WfProcessBusiness processBusiness = processBusinessService.getOne(query);
                // 流程状态为4、5说明流程已结束
                if (processBusiness != null && !StrUtil.equalsAny(processBusiness.getBusStatus(),
                        BizStatusEnums.BUSINESS_STATUS_4.getStatus(), BizStatusEnums.BUSINESS_STATUS_5.getStatus())) {
                    return Result.ERROR(ResponseEnum.HZQRD_APPLY_PROCESS_NOT_FINISH_ERROR);
                }
                // 如果该蓝字发票存在未开具的红字确认单或已开具未上传的红字发票，也不允许再次提交红字确认单申请流程
                if (!CommonEnum.YKJHZFP_YES.getKey().equals(approvalHzqrd.getYkjhzfpbz())
                        && CommonEnum.HZQRD_YXBZ_YES.getKey().equals(approvalHzqrd.getYxbz())) {
                    return Result.ERROR(ResponseEnum.HZQRD_APPLY_NOT_ISSUE_ERROR);
                }
            }
        }

        /*
        若无蓝票信息，需通过乐企归集能力中“批量发票下载申请”、“批量发票下载申请反馈”、“查询增量发票下载信息”接口查询蓝票信息。
        若无蓝票状态信息，需通过“发票用途状态信息查询”接口查询蓝字发票状态信息。
        异常凭证状态：发票异常凭证状态须为“01：正常”，否则提示：“选定的蓝字发票存在异常凭证状态！不允许发起红字确认单申请！”
        红字锁定标识：发票红字锁定标识须为“N：未锁定”，否则提示：“选定的蓝字发票存在红字锁定标识！不允许发起红字确认单申请！”
        */
        // todo 通过“发票用途状态信息查询”接口查询蓝字发票状态信息
        // 发票用途，调不了接口先固定为1
        String fpyt = "1";
        // 发票入账状态，调不了接口先固定为02
        String fprzzt = "02";
        // 增值税用途标签，调不了接口先固定为0
        String zzsyhyt = "0";
        // 消费税用途标签，调不了接口先固定为01
        String xfsyt = "01";
        // 异常凭证状态，调不了接口先固定为01
        String ycpzzt = "01";
        // 红字锁定标识，调不了接口先固定为N
        String hzsdbs = "N";
        if (!CommonEnum.YCPZZT_01.getKey().equals(ycpzzt)) {
            return Result.ERROR(ResponseEnum.HZQRD_YCPZZT_ERROR);
        }
        if (!CommonEnum.HZSDBS_N.getKey().equals(hzsdbs)) {
            return Result.ERROR(ResponseEnum.HZQRD_HZSDBS_ERROR);
        }

        /*
         若发票类型为“增值税专用发票”或“增值税普通发票”，则“是否纸质发票”标识为“是”置灰，不可编辑；
         若发票类型为“数电专票”、“数电普票”或“电子发票”，则“是否纸质发票”标识为“否”置灰，不可编辑。
        */
        List<DefBizdictVo> sfzzfpSelect = new ArrayList<>();
        if (StrUtil.equalsAny(invoiceVo.getFppz(), CommonEnum.INVOICE_TYPE_004.getKey(), CommonEnum.INVOICE_TYPE_007.getKey())) {
            DefBizdictVo sfzzfp_yes = new DefBizdictVo();
            sfzzfp_yes.setLxxdm(CommonEnum.SFZZFP_YES.getKey());
            sfzzfp_yes.setLxxmc(CommonEnum.SFZZFP_YES.getValue());
            sfzzfpSelect.add(sfzzfp_yes);
        }
        if (StrUtil.equalsAny(invoiceVo.getFppz(), CommonEnum.INVOICE_TYPE_01.getKey(), CommonEnum.INVOICE_TYPE_02.getKey(),
                CommonEnum.INVOICE_TYPE_026.getKey())) {
            DefBizdictVo sfzzfp_no = new DefBizdictVo();
            sfzzfp_no.setLxxdm(CommonEnum.SFZZFP_NO.getKey());
            sfzzfp_no.setLxxmc(CommonEnum.SFZZFP_NO.getValue());
            sfzzfpSelect.add(sfzzfp_no);
        }

        /*
        1.当根据选定的蓝字发票判断当前登录机构为“购方”时，查询发票用途为“0：未使用 ”或发票入账状态为“01：未入账”、“03：已入账撤销”时，提示：
        “购买方未勾选入账的发票，仅允许销售方发起红字确认单申请！”；
        2.当录入方身份为销方且仅当发票用途状态为“0：未使用”，或发票入账状态为“01：未入账”时，红冲类型只能是“全额红冲”
        3.当发票入账状态不为为“0：未使用”时，红冲类型默认带入“全额红冲”支持下拉选择“部分红冲”
        */
        // 冲红类型下拉框
        List<DefBizdictVo> chlxSelect = new ArrayList<>();
        DefBizdictVo invoiceStatus7 = new DefBizdictVo();
        invoiceStatus7.setLxxdm(CommonEnum.INVOICE_STATUS_7.getKey());
        invoiceStatus7.setLxxmc(CommonEnum.INVOICE_STATUS_7.getValue());
        DefBizdictVo invoiceStatus8 = new DefBizdictVo();
        invoiceStatus8.setLxxdm(CommonEnum.INVOICE_STATUS_8.getKey());
        invoiceStatus8.setLxxmc(CommonEnum.INVOICE_STATUS_8.getValue());
        chlxSelect.add(invoiceStatus7);
        chlxSelect.add(invoiceStatus8);

        // 红冲差额征税蓝票时，必须全额红冲
        if (CommonEnum.CEZS_02.getKey().equals(invoiceVo.getCezslxdm())) {
            chlxSelect.removeIf(item -> CommonEnum.INVOICE_STATUS_7.getKey().equals(item.getLxxdm()));
        }

        // 判断录入方身份 0：销方 1：购方
        String lrfsf;
        String nsrsbh = vmsEnterpriseInfoService.getNsrsbh();
        if (StringUtils.isNotBlank(nsrsbh) && nsrsbh.equals(invoiceVo.getGmfnsrsbh())) {
            lrfsf = CommonEnum.LRFSF_GMF.getKey();
            /*
                当根据选定的蓝字发票判断当前登录机构为“购方”时，查询发票用途为“0：未使用 ”或发票入账状态为“01：未入账”、“03：已入账撤销”时，
                提示：“购买方未勾选入账的发票，仅允许销售方发起红字确认单申请！”
            */
            if (CommonEnum.INVOICE_USE_0.getKey().equals(fpyt) || CommonEnum.INVOICE_RECORD_01.getKey().equals(fprzzt)
                    || CommonEnum.INVOICE_RECORD_03.getKey().equals(fprzzt)) {
                return Result.ERROR(ResponseEnum.HZQRD_GMF_RECORD_ERROR);
            }
            /*
                当蓝字发票对应的“增值税用途标签"为空、“消费税用途标签"为“未勾选库存”、“入账 状态标签"为“未入账”或“已入账撤销”时，
                红字信息只允许销售方发起(除非蓝字发票为收购发票)且只能进行全额冲红。
            */
            if (StringUtils.isBlank(zzsyhyt) || CommonEnum.XFSYT_00.getKey().equals(xfsyt)) {
                return Result.ERROR(ResponseEnum.HZQRD_GMF_RECORD_ERROR2);
            }
        } else if (StringUtils.isNotBlank(nsrsbh) && nsrsbh.equals(invoiceVo.getXsfnsrsbh())) {
            lrfsf = CommonEnum.LRFSF_XSF.getKey();
            // 判断发票用途、发票入账状态，当发票用途状态为“0：未使用 ”，或发票入账状态为“01：未入账”时，红冲类型只能是“全额红冲”
            // 20240402新增：当蓝字发票对应的“增值税用途标签"为空、“消费税用途标签"为“未勾选库存”、“入账状态标签"为“未入账”或“已入账撤销”时，只能进行全额冲红
            if (CommonEnum.INVOICE_USE_0.getKey().equals(fpyt) || CommonEnum.INVOICE_RECORD_01.getKey().equals(fprzzt)
                    || CommonEnum.INVOICE_RECORD_03.getKey().equals(fprzzt) || StringUtils.isBlank(zzsyhyt) || CommonEnum.XFSYT_00.getKey().equals(xfsyt)) {
                chlxSelect.removeIf(item -> CommonEnum.INVOICE_STATUS_7.getKey().equals(item.getLxxdm()));
            }
        } else {
            return Result.ERROR(ResponseEnum.LRFSF_UNKNOWN_ERROR);
        }

        // 判断购买方是否抵扣/入账
        String gmfsfdkrz = CommonConstant.STR_N;
        // 等进项接口通了再放开
        /*if (CommonEnum.INVOICE_USE_1.getKey().equals(fpyt) || CommonEnum.INVOICE_RECORD_02.getKey().equals(fprzzt)) {
            gmfsfdkrz = CommonConstant.STR_Y;
        } else {
            gmfsfdkrz = CommonConstant.STR_N;
        }*/

        // 查找发票明细信息，并计算各个明细的可冲销数量、可冲销金额、可冲销税额
        List<InvoiceItemVo> invoiceItemVoList = invoiceVo.getInvoiceItemVoList();

        // 计算已经冲红的数量、金额、税额
        Map<Long, Map<String, BigDecimal>> hasBeenRedMap = calculateHasBeenRed(invoiceVo.getFpdm(), invoiceVo.getFphm());

        List<VmsApprovalHzqrdItemVo> hzqrdItemVoList = BeanUtils.copyListProperties(invoiceItemVoList, VmsApprovalHzqrdItemVo::new, (s, t) -> {
            t.setLzmxxh(s.getMxxh());
        });
        // 计算可冲销数量、可冲销金额、可冲销税额
        Iterator<VmsApprovalHzqrdItemVo> iterator = hzqrdItemVoList.iterator();
        while (iterator.hasNext()) {
            VmsApprovalHzqrdItemVo hzqrdItemVo = iterator.next();
            Map<String, BigDecimal> map = hasBeenRedMap.get(hzqrdItemVo.getLzmxxh());
            if (map != null && !map.isEmpty()) {
                // 可冲销数量、可冲销金额、可冲销税额赋值
                if (StringUtils.isNotBlank(hzqrdItemVo.getSl())) {
                    hzqrdItemVo.setKcxsl(new BigDecimal(hzqrdItemVo.getSl()).subtract(map.get("slTotal")));
                    hzqrdItemVo.setCxsl(hzqrdItemVo.getKcxsl().negate());
                }
                hzqrdItemVo.setKcxje(hzqrdItemVo.getJe().subtract(map.get("jeTotal")));
                hzqrdItemVo.setKcxse(hzqrdItemVo.getSe().subtract(map.get("seTotal")));
                // 冲销数量、冲销金额、冲销税额赋值，默认为全部冲销
                hzqrdItemVo.setCxje(hzqrdItemVo.getKcxje().negate());
                hzqrdItemVo.setCxse(hzqrdItemVo.getKcxse().negate());
                // 如果可冲销金额、可冲销税额小于等于0，说明此条明细被全额红冲，不返回前端
                // 出现一条明细被多次红冲，总的红冲税额比蓝票多一分的情况，所以加上小于0的情况
                if (hzqrdItemVo.getKcxje().compareTo(BigDecimal.ZERO) <= 0
                        && hzqrdItemVo.getKcxse().compareTo(BigDecimal.ZERO) <= 0) {
                    iterator.remove();
                }
            } else {
                // 说明此条明细没有被红冲过，可冲销数量、可冲销金额、可冲销税额就是明细的数量、金额、税额
                if (StringUtils.isNotBlank(hzqrdItemVo.getSl())) {
                    hzqrdItemVo.setKcxsl(new BigDecimal(hzqrdItemVo.getSl()));
                    hzqrdItemVo.setCxsl(hzqrdItemVo.getKcxsl().negate());
                }
                hzqrdItemVo.setKcxje(hzqrdItemVo.getJe());
                hzqrdItemVo.setKcxse(hzqrdItemVo.getSe());
                // 冲销数量、冲销金额、冲销税额赋值，默认为全部冲销
                hzqrdItemVo.setCxje(hzqrdItemVo.getKcxje().negate());
                hzqrdItemVo.setCxse(hzqrdItemVo.getKcxse().negate());
            }
        }
        if (CollectionUtil.isEmpty(hzqrdItemVoList)) {
            return Result.ERROR(ResponseEnum.INVOICE_ALL_RED_ERROR);
        }

        VmsApprovalHzqrdTotalSimpleVo totalVo = new VmsApprovalHzqrdTotalSimpleVo();
        VmsApprovalHzqrdSimpleVo hzqrdSimpleVo = new VmsApprovalHzqrdSimpleVo();

        hzqrdSimpleVo.setLzfpdm(fpdm);
        hzqrdSimpleVo.setLzfphm(fphm);
        hzqrdSimpleVo.setLrfsf(lrfsf);
        hzqrdSimpleVo.setGmfsfdkrz(gmfsfdkrz);
        hzqrdSimpleVo.setChlxSelect(chlxSelect);
        hzqrdSimpleVo.setSfzzfpSelect(sfzzfpSelect);
        // 两个下拉框赋默认值
        hzqrdSimpleVo.setChlx(chlxSelect.get(chlxSelect.size()-1).getLxxdm());
        hzqrdSimpleVo.setSfzzfpbz(sfzzfpSelect.get(0).getLxxdm());

        totalVo.setVmsApprovalHzqrdSimpleVo(hzqrdSimpleVo);
        totalVo.setVmsApprovalHzqrdItemVoList(hzqrdItemVoList);
        return Result.OK(totalVo);
    }

    /**
     * 根据老系统数据计算蓝票明细已经冲红的数量、金额、税额
     * @param fpdm 蓝字发票代码
     * @param fphm 蓝字发票号码
     * @return map中key为蓝字明细序号，value为已冲销数量、金额、税额
     */
    @Override
    public Map<Long, Map<String, BigDecimal>> calculateHasBeenRed(String fpdm, String fphm) {
        // map中key为蓝字明细序号，value为已冲销数量、金额、税额
        Map<Long, Map<String, BigDecimal>> hasBeenRedMap = new HashMap<>();

        // 蓝票发票号码为空，直接返回
        if (StringUtils.isBlank(fphm)) {
            return hasBeenRedMap;
        }

        LambdaQueryWrapper<NvatOutInvoiceDetails> invoiceQuery = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(fpdm)) {
            invoiceQuery.eq(NvatOutInvoiceDetails::getFpdm, fpdm);
        }
        invoiceQuery.eq(NvatOutInvoiceDetails::getFphm, fphm);
        NvatOutInvoiceDetails nvatInvoice = nvatOutInvoiceDetailsMapper.selectOne(invoiceQuery);
        // 老系统未查到蓝字发票信息，直接返回
        if (nvatInvoice == null) {
            return hasBeenRedMap;
        }

        LambdaQueryWrapper<NvatOutInvoiceItems> itemQuery = new LambdaQueryWrapper<>();
        itemQuery.eq(NvatOutInvoiceItems::getOidid, nvatInvoice.getOidid());
        itemQuery.orderByAsc(NvatOutInvoiceItems::getIviid);
        List<NvatOutInvoiceItems> nvatInvoiceItemList = nvatOutInvoiceItemsMapper.selectList(itemQuery);
        // 老系统未查到蓝字发票明细信息，直接返回
        if (CollectionUtil.isEmpty(nvatInvoiceItemList)) {
            return hasBeenRedMap;
        }
        // 给老系统蓝字发票明细赋值明细序号，后续计算明细冲销金额税额时使用
        for (int i = 0; i < nvatInvoiceItemList.size(); i++) {
            NvatOutInvoiceItems invoiceItem = nvatInvoiceItemList.get(i);
            invoiceItem.setMxxh((long) i + 1);
        }

        LambdaQueryWrapper<NvatOutInvomapSelf> selfQuery = new LambdaQueryWrapper<>();
        selfQuery.eq(NvatOutInvomapSelf::getOoidid, nvatInvoice.getOidid());
        selfQuery.orderByAsc(NvatOutInvomapSelf::getOiviid);
        List<NvatOutInvomapSelf> nvatSelfList = nvatOutInvomapselfMapper.selectList(selfQuery);
        // 老系统红蓝票关联关系表未查到数据，说明该蓝票没有被红冲过，直接返回
        if (CollectionUtil.isEmpty(nvatSelfList)) {
            return hasBeenRedMap;
        }

        // 存放该蓝字发票所有红冲的红票明细信息
        List<NvatOutInvoiceItems> nvatRedItemList = new ArrayList<>();
        for (NvatOutInvomapSelf nvatSelf : nvatSelfList) {
            // 红票明细表id
            Long niviid = nvatSelf.getNiviid();
            LambdaQueryWrapper<NvatOutInvoiceItems> redItemQuery = new LambdaQueryWrapper<>();
            redItemQuery.eq(NvatOutInvoiceItems::getIviid, niviid);
            NvatOutInvoiceItems nvatRedInvoiceItem = nvatOutInvoiceItemsMapper.selectOne(redItemQuery);
            // 1.根据红字发票明细id，查询红蓝票关联关系表，得到蓝字发票明细id
            Optional<NvatOutInvomapSelf> first = nvatSelfList.stream().filter(a -> nvatRedInvoiceItem.getIviid().equals(a.getNiviid())).findFirst();
            if (!first.isPresent()) {
                throw new BusinessException(ResponseEnum.INVOICE_ITEM_NOT_FIND_ERROR);
            }
            NvatOutInvomapSelf nvatOutInvomapSelf = first.get();
            // 2.再根据蓝字发票明细id，查询老系统蓝字发票明细，得到蓝字明细序号
            Optional<NvatOutInvoiceItems> first2 = nvatInvoiceItemList.stream().filter(a -> nvatOutInvomapSelf.getOiviid().equals(a.getIviid())).findFirst();
            if (!first2.isPresent()) {
                throw new BusinessException(ResponseEnum.INVOICE_ITEM_NOT_FIND_ERROR);
            }
            NvatOutInvoiceItems invoiceItems = first2.get();
            nvatRedInvoiceItem.setLzmxxh(invoiceItems.getMxxh());

            nvatRedItemList.add(nvatRedInvoiceItem);
        }

        // map中key为蓝字明细序号，value为申请红冲的明细
        Map<Long, List<NvatOutInvoiceItems>> groupMap = nvatRedItemList.stream().collect(Collectors.groupingBy(NvatOutInvoiceItems::getLzmxxh));
        for (Map.Entry<Long, List<NvatOutInvoiceItems>> entry : groupMap.entrySet()) {
            log.info("{}根据蓝字明细序号分组：Key = {}, Value = {}", LOG_MSG, entry.getKey(), JSONObject.toJSONString(entry.getValue()));
            // 总数量、总金额、总税额
            BigDecimal slTotal = BigDecimal.ZERO, jeTotal = BigDecimal.ZERO, seTotal = BigDecimal.ZERO;
            for (NvatOutInvoiceItems invoiceItem : entry.getValue()) {
                if (ObjectUtil.isNotEmpty(invoiceItem.getGmsl())) {
                    slTotal = slTotal.add(invoiceItem.getGmsl().abs());
                }
                jeTotal = jeTotal.add(invoiceItem.getJe().abs());
                seTotal = seTotal.add(invoiceItem.getSe().abs());
            }
            Map<String, BigDecimal> map = new HashMap<>();
            map.put("slTotal", slTotal);
            map.put("jeTotal", jeTotal);
            map.put("seTotal", seTotal);
            hasBeenRedMap.put(entry.getKey(), map);
        }
        return hasBeenRedMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> saveApply(VmsApprovalHzqrdTotalDto applyDto) {
        // 数据校验
        VmsApprovalHzqrdDto hzqrdDto = applyDto.getVmsApprovalHzqrdDto();
        if (ObjectUtil.isEmpty(hzqrdDto) || ObjectUtil.isEmpty(hzqrdDto.getApplyId())) {
            return Result.ERROR(ResponseEnum.HZQRD_MAIN_EMPTY_ERROR);
        }
        List<VmsApprovalHzqrdItemDto> hzqrdItemDtoList = applyDto.getVmsApprovalHzqrdItemDtoList();
        if (CollectionUtil.isEmpty(hzqrdItemDtoList)) {
            return Result.ERROR(ResponseEnum.HZQRD_ITEM_EMPTY_ERROR);
        }

        // 保存数据时也要走一遍快速添加的校验
        Result<VmsApprovalHzqrdTotalSimpleVo> result = fastAdd(hzqrdDto.getLzfpdm(), hzqrdDto.getLzfphm(), hzqrdDto.getApplyId());
        if (!ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
            return Result.ERROR(result.getCode(), result.getMessage());
        }
        VmsApprovalHzqrdSimpleVo fastAddSimpleVo = result.getData().getVmsApprovalHzqrdSimpleVo();

        // 查询发票主信息和明细信息
        InvoiceVo invoiceVo = commonInvoiceService.queryInvoice(hzqrdDto.getLzfpdm(), hzqrdDto.getLzfphm(), true);
        List<InvoiceItemVo> invoiceItemVoList = invoiceVo.getInvoiceItemVoList();

        // 红冲差额征税蓝票时，必须全额红冲
        if (CommonEnum.CEZS_02.getKey().equals(invoiceVo.getCezslxdm())
                && CommonEnum.INVOICE_STATUS_7.getKey().equals(hzqrdDto.getChlx())) {
            return Result.ERROR(ResponseEnum.HZQRD_CEZS_CHLX_ERROR);
        }

        // 校验冲销数量、冲销金额、冲销税额
        Result<Object> checkResult = checkChSlJeSe(hzqrdDto.getChyydm(), invoiceVo.getCezslxdm(),
                                                   hzqrdItemDtoList, invoiceItemVoList);
        if (!ResponseEnum.SUCCESS.getCode().equals(checkResult.getCode())) {
            return checkResult;
        }

        // 如果冲销数量、冲销金额、冲销税额都等于可冲销数量、可冲销金额、可冲销税额，则将冲红原因改为全额冲红
        boolean isAllRed = false;
        for (VmsApprovalHzqrdItemDto hzqrdItemDto : hzqrdItemDtoList) {
            if (ObjectUtil.isNotEmpty(hzqrdItemDto.getKcxsl()) && ObjectUtil.isNotEmpty(hzqrdItemDto.getCxsl())) {
                if (hzqrdItemDto.getKcxsl().abs().compareTo(hzqrdItemDto.getCxsl().abs()) == 0
                    && hzqrdItemDto.getKcxje().abs().compareTo(hzqrdItemDto.getCxje().abs()) == 0
                    && hzqrdItemDto.getKcxse().abs().compareTo(hzqrdItemDto.getCxse().abs()) == 0) {
                    isAllRed = true;
                }
            } else {
                if (hzqrdItemDto.getKcxje().abs().compareTo(hzqrdItemDto.getCxje().abs()) == 0
                    && hzqrdItemDto.getKcxse().abs().compareTo(hzqrdItemDto.getCxse().abs()) == 0) {
                    isAllRed = true;
                }
            }
        }
        if (isAllRed) {
            hzqrdDto.setChlx(CommonEnum.INVOICE_STATUS_8.getKey());
        }

        // 组装红字确认单申请流程表-明细表数据
        List<VmsApprovalHzqrdItem> hzqrdItemList = convertToVmsApprovalHzqrdItem(hzqrdItemDtoList, invoiceItemVoList);

        // 组装红字确认单申请流程表-主表数据
        VmsApprovalHzqrd hzqrd = convertToVmsApprovalHzqrd(hzqrdDto, invoiceVo);
        hzqrd.setGmfsfdkrz(fastAddSimpleVo.getGmfsfdkrz());
        hzqrd.setHzcxje(hzqrdItemList.stream().map(VmsApprovalHzqrdItem::getJe).reduce(BigDecimal.ZERO, BigDecimal::add));
        hzqrd.setHzcxse(hzqrdItemList.stream().map(VmsApprovalHzqrdItem::getSe).reduce(BigDecimal.ZERO, BigDecimal::add));
        hzqrd.setHzqrdmxsl((long) hzqrdItemList.size());

        // 主表数据入库
        LambdaQueryWrapper<VmsApprovalHzqrd> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(VmsApprovalHzqrd::getApplyId, hzqrdDto.getApplyId());
        VmsApprovalHzqrd approvalHzqrd = vmsApprovalHzqrdService.getOne(wrapper);
        if (approvalHzqrd == null) {
            vmsApprovalHzqrdService.save(hzqrd);
        } else {
            hzqrd.setId(approvalHzqrd.getId());
            hzqrd.setCreatTime(approvalHzqrd.getCreatTime());
            hzqrd.setCreatBy(approvalHzqrd.getCreatBy());
            vmsApprovalHzqrdService.updateById(hzqrd);
            // 明细表数据删除后再重新入库
            LambdaQueryWrapper<VmsApprovalHzqrdItem> itemWrapper = new LambdaQueryWrapper<>();
            itemWrapper.eq(VmsApprovalHzqrdItem::getHzqrdId, hzqrd.getId());
            vmsApprovalHzqrdItemService.remove(itemWrapper);
        }

        // 红字申请单明细数据赋值
        for (VmsApprovalHzqrdItem approvalHzqrdItem : hzqrdItemList) {
            approvalHzqrdItem.setHzqrdId(hzqrd.getId());
            // 销售折让情况，清空明细行的数量和单价
            if (CommonEnum.CHYY_04.getKey().equals(hzqrdDto.getChyydm())) {
                approvalHzqrdItem.setFpspdj(null);
                approvalHzqrdItem.setFpspsl(null);
            }
        }
        vmsApprovalHzqrdItemService.saveBatch(hzqrdItemList);

        return Result.OK();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> revokeApply(Long id) {
        LambdaQueryWrapper<VmsApprovalHzqrd> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(VmsApprovalHzqrd::getId, id);
        VmsApprovalHzqrd approvalHzqrd = vmsApprovalHzqrdService.getOne(wrapper);
        if (approvalHzqrd == null) {
            return Result.ERROR(ResponseEnum.HZQRD_NOT_FIND_ERROR);
        }
        // 红字确认单撤销时要求红字确认单有效状态为有效且未开具红票
        if (!CommonEnum.HZQRD_YXBZ_YES.getKey().equals(approvalHzqrd.getYxbz()) || !CommonEnum.YKJHZFP_NO.getKey().equals(approvalHzqrd.getYkjhzfpbz())) {
            return Result.ERROR(ResponseEnum.HZQRD_REVOKE_ERROR);
        }
        // 红字确认单撤销时要求红字确认单状态为：“01”无需确认、“02”销方录入待购方确认、“03”购方录入待销方确认
        if (!StrUtil.equalsAny(approvalHzqrd.getHzqrxxztdm(), CommonEnum.HZQRD_STATUS_01.getKey(), CommonEnum.HZQRD_STATUS_02.getKey(), CommonEnum.HZQRD_STATUS_03.getKey())) {
            return Result.ERROR(ResponseEnum.HZQRD_REVOKE_ERROR2);
        }
        // 调用乐企数电红字确认单确认接口完成红字确认单撤销
        ConfirmRedConfirmParam param = new ConfirmRedConfirmParam();
        param.setXsfnsrsbh(approvalHzqrd.getXsfnsrsbh());
        param.setUuid(approvalHzqrd.getUuid());
        param.setHzqrdbh(approvalHzqrd.getHzfpxxqrdbh());
        param.setQrlx(CommonEnum.HZQRD_QRLX_C.getKey());
        param.setCreateUser(SecurityUtils.getUserCode());
        param.setDeptCode(SecurityUtils.getDeptCode());
        Result<ConfirmRedConfirmVO> result = dmzApiClientService.confirmRedConfirm(param, null);
        if (!ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
            return Result.ERRORT(result.getCode(), result.getMessage());
        }
        log.info("{}调用DMZ数电红字确认单确认接口完成红字确认单撤销成功", LOG_MSG);

        // 调用乐企接口查询数电红字确认单明细信息
        QueryRedConfirmDetailParam itemParam = new QueryRedConfirmDetailParam();
        itemParam.setXsfnsrsbh(approvalHzqrd.getXsfnsrsbh());
        itemParam.setUuid(approvalHzqrd.getUuid());
        itemParam.setCreateUser(SecurityUtils.getUserCode());
        itemParam.setDeptCode(SecurityUtils.getDeptCode());
        Result<QueryRedConfirmDetailVO> itemResult = dmzApiClientService.queryRedConfirmDetail(itemParam, null);
        if (!ResponseEnum.SUCCESS.getCode().equals(itemResult.getCode())) {
            return Result.ERRORT(itemResult.getCode(), itemResult.getMessage());
        }
        log.info("{}调用DMZ查询数电红字确认单明细成功", LOG_MSG);
        // 更新本地流程表和本地乐企表
        String hzqrxxztdm = itemResult.getData().getHzqrxxztDm();
        approvalHzqrd.setQrrq(result.getData().getQrrq());
        approvalHzqrd.setHzqrxxztdm(hzqrxxztdm);
        approvalHzqrd.setYxbz(CommonEnum.HZQRD_YXBZ_NO.getKey());
        approvalHzqrd.setUpdateTime(new Date());
        approvalHzqrd.setUpdateBy(SecurityUtils.getUserCode());
        vmsApprovalHzqrdService.updateById(approvalHzqrd);

        LambdaQueryWrapper<VmsLeqiHzqrd> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(VmsLeqiHzqrd::getHzfpxxqrdbh, approvalHzqrd.getHzfpxxqrdbh());
        wrapper2.eq(VmsLeqiHzqrd::getQydjid, SecurityUtils.getDeptCode());
        VmsLeqiHzqrd leqiHzqrd = vmsLeqiHzqrdService.getOne(wrapper2);
        if (leqiHzqrd != null) {
            leqiHzqrd.setQrrq(result.getData().getQrrq());
            leqiHzqrd.setHzqrxxztdm(hzqrxxztdm);
            leqiHzqrd.setYxbz(CommonEnum.HZQRD_YXBZ_NO.getKey());
            leqiHzqrd.setUpdateTime(new Date());
            leqiHzqrd.setUpdateBy(SecurityUtils.getUserCode());
            vmsLeqiHzqrdService.updateById(leqiHzqrd);
        }

        return Result.OK();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> hzqrdApply(Long applyId) {
        LambdaQueryWrapper<VmsApprovalHzqrd> hzqrdWrapper = new LambdaQueryWrapper<>();
        hzqrdWrapper.eq(VmsApprovalHzqrd::getApplyId, applyId);
        VmsApprovalHzqrd hzqrd = vmsApprovalHzqrdService.getOne(hzqrdWrapper);
        if (hzqrd == null) {
            return Result.ERROR(ResponseEnum.HZQRD_NOT_FIND_ERROR);
        }
        LambdaQueryWrapper<VmsApprovalHzqrdItem> itemWrapper = new LambdaQueryWrapper<>();
        itemWrapper.eq(VmsApprovalHzqrdItem::getHzqrdId, hzqrd.getId());
        itemWrapper.orderByAsc(VmsApprovalHzqrdItem::getXh);
        List<VmsApprovalHzqrdItem> hzqrdItemList = vmsApprovalHzqrdItemService.list(itemWrapper);

        // 调用乐企数电红字确认单申请接口完成红字确认单申请
        ApplyRedConfirmDetailParam param = new ApplyRedConfirmDetailParam();
        BeanUtils.copyProperties(hzqrd, param);
        // 字段名不一样
        param.setLzfppzDm(hzqrd.getLzfppzdm());
        param.setLzfpTdyslxDm(hzqrd.getLzfptdyslxdm());
        param.setChyyDm(hzqrd.getChyydm());
        param.setCreateUser(SecurityUtils.getUserCode());
        param.setDeptCode(SecurityUtils.getDeptCode());
        param.setLzkprq(DateUtil.format(hzqrd.getLzkprq(), CommonConstant.DATE_FORMAT_14));
        // 红字确认单明细
        List<ApplyRedConfirmDetailParam.Hzqrxxmx> hzqrdmxList = BeanUtils.copyListProperties(hzqrdItemList, ApplyRedConfirmDetailParam.Hzqrxxmx::new);
        param.setHzqrdmxList(hzqrdmxList);

        Result<ApplyRedConfirmVO> result = dmzApiClientService.applyRedConfirm(param, null);
        if (!ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
            return Result.ERRORT(result.getCode(), result.getMessage());
        }

        // 乐企返回数据
        ApplyRedConfirmVO resultData = result.getData();

        hzqrd.setUuid(resultData.getUuid());
        hzqrd.setHzfpxxqrdbh(resultData.getHzfpxxqrdbh());
        hzqrd.setHzqrxxztdm(resultData.getHzqrxxztDm());
        if (StrUtil.equalsAny(resultData.getHzqrxxztDm(), HzqrdStatusEnum.HZQRD_STATUS_01.getKey(), HzqrdStatusEnum.HZQRD_STATUS_04.getKey())) {
            hzqrd.setQrrq(new Date());
        }
        hzqrd.setLrrq(new Date());
        hzqrd.setUpdateTime(new Date());
        hzqrd.setUpdateBy(SecurityUtils.getUserCode());
        hzqrd.setApprovalBy(SecurityUtils.getUserCode());
        vmsApprovalHzqrdService.updateById(hzqrd);

        hzqrdItemList = hzqrdItemList.stream().peek(hzqrdItem -> hzqrdItem.setHzfpxxqrdbh(resultData.getHzfpxxqrdbh()))
                .collect(Collectors.toList());
        vmsApprovalHzqrdItemService.updateBatchById(hzqrdItemList);

        // 组装红字确认单乐企返回-主表数据
        VmsLeqiHzqrd leqiHzqrd = new VmsLeqiHzqrd();
        BeanUtils.copyBeanProp(leqiHzqrd, hzqrd);
        // 判断红字确认单来源 0：我发出的红字确认单 1：我收到的红字确认单
        String hzqrdSource = judgeHzqrdSource(hzqrd, vmsEnterpriseInfoService.getNsrsbh());
        leqiHzqrd.setHzqrdly(hzqrdSource);
        leqiHzqrd.setLrrq(hzqrd.getCreatTime());
        leqiHzqrd.setQydjid(SecurityUtils.getDeptCode());
        leqiHzqrd.setCreatTime(new Date());
        leqiHzqrd.setCreatBy(SecurityUtils.getUserCode());
        leqiHzqrd.setUpdateTime(new Date());
        leqiHzqrd.setUpdateBy(SecurityUtils.getUserCode());
        vmsLeqiHzqrdService.save(leqiHzqrd);

        // 组装红字确认单乐企返回-明细表数据
        List<VmsLeqiHzqrdItem> leqiHzqrdItemList = BeanUtils.copyListProperties(hzqrdItemList, VmsLeqiHzqrdItem::new, (s, t) -> {
            t.setHzqrdId(leqiHzqrd.getId());
            t.setHzfpxxqrdbh(resultData.getHzfpxxqrdbh());
        });
        vmsLeqiHzqrdItemService.saveBatch(leqiHzqrdItemList);

        return Result.OK();
    }

    @Override
    public Result<VmsApprovalHzqrdTotalSimpleVo> getApplyDetail(Long applyId) {
        LambdaQueryWrapper<VmsApprovalHzqrd> hzqrdWrapper = new LambdaQueryWrapper<>();
        hzqrdWrapper.eq(VmsApprovalHzqrd::getApplyId, applyId);
        VmsApprovalHzqrd approvalHzqrd = vmsApprovalHzqrdService.getOne(hzqrdWrapper);
        if (approvalHzqrd == null) {
            return Result.ERROR(ResponseEnum.HZQRD_NOT_FIND_ERROR);
        }
        LambdaQueryWrapper<VmsApprovalHzqrdItem> itemWrapper = new LambdaQueryWrapper<>();
        itemWrapper.eq(VmsApprovalHzqrdItem::getHzqrdId, approvalHzqrd.getId());
        itemWrapper.orderByAsc(VmsApprovalHzqrdItem::getXh);
        List<VmsApprovalHzqrdItem> hzqrdItemList = vmsApprovalHzqrdItemService.list(itemWrapper);

        // todo 通过“发票用途状态信息查询”接口查询蓝字发票状态信息
        // 发票用途，调不了接口先固定为1
        String fpyt = "1";
        // 发票入账状态，调不了接口先固定为02
        String fprzzt = "02";

        // 冲红类型下拉框
        List<DefBizdictVo> chlxSelect = new ArrayList<>();
        DefBizdictVo invoiceStatus7 = new DefBizdictVo();
        invoiceStatus7.setLxxdm(CommonEnum.INVOICE_STATUS_7.getKey());
        invoiceStatus7.setLxxmc(CommonEnum.INVOICE_STATUS_7.getValue());
        DefBizdictVo invoiceStatus8 = new DefBizdictVo();
        invoiceStatus8.setLxxdm(CommonEnum.INVOICE_STATUS_8.getKey());
        invoiceStatus8.setLxxmc(CommonEnum.INVOICE_STATUS_8.getValue());
        chlxSelect.add(invoiceStatus7);
        chlxSelect.add(invoiceStatus8);

        // 是否纸质发票下拉框
        List<DefBizdictVo> sfzzfpSelect = new ArrayList<>();
        if (CommonEnum.SFZZFP_YES.getKey().equals(approvalHzqrd.getSfzzfpbz())) {
            DefBizdictVo sfzzfp_yes = new DefBizdictVo();
            sfzzfp_yes.setLxxdm(CommonEnum.SFZZFP_YES.getKey());
            sfzzfp_yes.setLxxmc(CommonEnum.SFZZFP_YES.getValue());
            sfzzfpSelect.add(sfzzfp_yes);
        } else {
            DefBizdictVo sfzzfp_no = new DefBizdictVo();
            sfzzfp_no.setLxxdm(CommonEnum.SFZZFP_NO.getKey());
            sfzzfp_no.setLxxmc(CommonEnum.SFZZFP_NO.getValue());
            sfzzfpSelect.add(sfzzfp_no);
        }

        // 判断录入方身份
        if (CommonEnum.LRFSF_XSF.getKey().equals(approvalHzqrd.getLrfsf())) {
            // 判断发票用途、发票入账状态，当发票用途状态为“0：未使用 ”，或发票入账状态为“01：未入账”时，红冲类型只能是“全额红冲”
            if (CommonEnum.INVOICE_USE_0.getKey().equals(fpyt) || CommonEnum.INVOICE_RECORD_01.getKey().equals(fprzzt)) {
                chlxSelect.remove(0);
            }
        }

        // 查询发票主信息和明细信息（可能是进项票、税控票、数电票）
        InvoiceVo invoiceVo = commonInvoiceService.queryInvoice(approvalHzqrd.getLzfpdm(), approvalHzqrd.getLzfphm(), true);
        if (invoiceVo == null) {
            return Result.ERROR(ResponseEnum.HZQRD_NO_INVOICE_ERROR);
        }
        List<InvoiceItemVo> invoiceItemVoList = invoiceVo.getInvoiceItemVoList();

        // 计算已经冲红的数量、金额、税额
        Map<Long, Map<String, BigDecimal>> hasBeenRedMap = calculateHasBeenRed(approvalHzqrd.getLzfpdm(), approvalHzqrd.getLzfphm());

        // 计算各个明细的可冲销数量、可冲销金额、可冲销税额
        List<VmsApprovalHzqrdItemVo> hzqrdItemVoList = new ArrayList<>();
        for (VmsApprovalHzqrdItem hzqrdItem : hzqrdItemList) {
            Optional<InvoiceItemVo> first = invoiceItemVoList.stream().filter(a -> hzqrdItem.getLzmxxh().equals(a.getMxxh())).findFirst();
            if (!first.isPresent()) {
                return Result.ERROR(ResponseEnum.INVOICE_NOT_FIND_ERROR);
            }
            InvoiceItemVo invoiceItem = first.get();
            VmsApprovalHzqrdItemVo hzqrdItemVo = new VmsApprovalHzqrdItemVo();
            /*
                此处需要注意：已开发票明细表中，数量和单价字段是sl、dj
                红字确认单明细表中，数量和单价字段是fpspsl、fpspdj
            */
            BeanUtils.copyBeanProp(hzqrdItemVo, invoiceItem);
            hzqrdItemVo.setLzmxxh(invoiceItem.getMxxh());

            Map<String, BigDecimal> map = hasBeenRedMap.get(hzqrdItemVo.getLzmxxh());
            if (map != null && !map.isEmpty()) {
                // 可冲销数量、可冲销金额、可冲销税额赋值
                if (StringUtils.isNotBlank(hzqrdItemVo.getSl())) {
                    hzqrdItemVo.setKcxsl(new BigDecimal(hzqrdItemVo.getSl()).subtract(map.get("slTotal")));
                }
                hzqrdItemVo.setKcxje(hzqrdItemVo.getJe().subtract(map.get("jeTotal")));
                hzqrdItemVo.setKcxse(hzqrdItemVo.getSe().subtract(map.get("seTotal")));
            } else {
                // 说明此条明细没有被红冲过，可冲销数量、可冲销金额、可冲销税额就是明细的数量、金额、税额
                if (StringUtils.isNotBlank(hzqrdItemVo.getSl())) {
                    hzqrdItemVo.setKcxsl(new BigDecimal(hzqrdItemVo.getSl()));
                }
                hzqrdItemVo.setKcxje(hzqrdItemVo.getJe());
                hzqrdItemVo.setKcxse(hzqrdItemVo.getSe());
            }
            // 冲销数量、冲销金额、冲销税额赋值
            if (StringUtils.isNotBlank(hzqrdItem.getFpspsl())) {
                hzqrdItemVo.setCxsl(new BigDecimal(hzqrdItem.getFpspsl()));
            }
            hzqrdItemVo.setCxje(hzqrdItem.getJe());
            hzqrdItemVo.setCxse(hzqrdItem.getSe());

            hzqrdItemVoList.add(hzqrdItemVo);
        }

        // 构造返回数据
        VmsApprovalHzqrdTotalSimpleVo totalSimple = new VmsApprovalHzqrdTotalSimpleVo();
        VmsApprovalHzqrdSimpleVo hzqrdSimpleVo = new VmsApprovalHzqrdSimpleVo();
        BeanUtils.copyBeanProp(hzqrdSimpleVo, approvalHzqrd);
        hzqrdSimpleVo.setSfzzfpSelect(sfzzfpSelect);
        hzqrdSimpleVo.setChlxSelect(chlxSelect);

        totalSimple.setVmsApprovalHzqrdSimpleVo(hzqrdSimpleVo);
        totalSimple.setVmsApprovalHzqrdItemVoList(hzqrdItemVoList);

        return Result.OK(totalSimple);
    }

    /**
     * 判断红字确认单来源
     * @param hzqrd 红字确认单信息
     * @param nsrsbh 登录机构税号
     * @return 0：我发出的红字确认单 1：我收到的红字确认单
     */
    private String judgeHzqrdSource(VmsApprovalHzqrd hzqrd, String nsrsbh) {
        if (StringUtils.isBlank(nsrsbh)) {
            throw new BusinessException(ResponseEnum.ENTERPRISEINFO_ERROR);
        }
        if (CommonEnum.LRFSF_GMF.getKey().equals(hzqrd.getLrfsf())) {
            return nsrsbh.equals(hzqrd.getGmfnsrsbh()) ? CommonEnum.HZQRD_SOURCE_0.getKey() : CommonEnum.HZQRD_SOURCE_1.getKey();
        } else {
            return nsrsbh.equals(hzqrd.getXsfnsrsbh()) ? CommonEnum.HZQRD_SOURCE_0.getKey() : CommonEnum.HZQRD_SOURCE_1.getKey();
        }
    }

    /**
     * 校验冲销数量、冲销金额、冲销税额
     * @param chyydm 冲红原因代码
     * @param cezslxdm 差额征税类型代码
     * @param hzqrdItemDtoList 前端传递的冲销数量、冲销金额、冲销税额
     * @param itemList 蓝字发票明细
     * @return OK/ERROR
     */
    private Result<Object> checkChSlJeSe(String chyydm, String cezslxdm, List<VmsApprovalHzqrdItemDto> hzqrdItemDtoList, List<InvoiceItemVo> itemList) {
        /*
        1)开票有误：红冲类型自动回显“全额红冲”置灰不可编辑，冲销数量、冲销金额以及冲销税额与可红冲数量、金额、税额保持一致；
        2)销货退回：如蓝字发票有数量，则只允许修改冲销数量，按照单价自动计算冲销金额和冲销税额；如蓝字发票没有数量仅有金额，则冲销数量默认为空，置灰不可修改，允许输入冲销金额，并依据税率自动计算冲销税额，其中冲销税额=蓝字发票明细行对应税率*冲销金额，保留小数点后两位；
        3)服务中止：允许输入冲销金额和冲销数量（若蓝字发票有），依据税率自动计算冲销税额，其中冲销税额=蓝字发票明细行对应税率*冲销金额，保留小数点后两位；
        4)销售折让：选择需折让的商品行，输入冲销金额，依据税率自动计算冲销税额，其中冲销税额=蓝字发票明细行对应税率*冲销金额，保留小数点后两位；
        */
        // 冲销数量需要处理为负数，重新计算冲销金额、冲销税额
        int num = 1;
        for (VmsApprovalHzqrdItemDto hzqrdItemDto : hzqrdItemDtoList) {
            // 冲销数量、冲销金额、冲销税额是负数，此处转为负数
            if (ObjectUtil.isNotEmpty(hzqrdItemDto.getCxsl())) {
                hzqrdItemDto.setCxsl(hzqrdItemDto.getCxsl().abs().negate());
            }
            if (ObjectUtil.isNotEmpty(hzqrdItemDto.getCxje())) {
                hzqrdItemDto.setCxje(hzqrdItemDto.getCxje().abs().negate());
            }
            if (ObjectUtil.isNotEmpty(hzqrdItemDto.getCxse())) {
                hzqrdItemDto.setCxse(hzqrdItemDto.getCxse().abs().negate());
            }
            // 根据明细id找到对应蓝票的明细
            Optional<InvoiceItemVo> first = itemList.stream().filter(a -> hzqrdItemDto.getId().equals(a.getId())).findFirst();
            if (!first.isPresent()) {
                return Result.ERROR(ResponseEnum.INVOICE_NOT_FIND_ERROR);
            }
            InvoiceItemVo invoiceItem = first.get();
            // 重新计算的冲销数量、冲销金额、冲销税额
            BigDecimal cxsl = BigDecimal.ZERO, cxje, cxse;
            // 明细行的单价和税率，后面计算时会用到
            String dj = invoiceItem.getDj();
            BigDecimal slv = invoiceItem.getSlv();

            if (CommonEnum.CHYY_01.getKey().equals(chyydm)) {
                // 判断可冲销数量是否为空
                if (ObjectUtil.isNotEmpty(hzqrdItemDto.getKcxsl())) {
                    if (hzqrdItemDto.getKcxsl().abs().compareTo(hzqrdItemDto.getCxsl().abs()) != 0
                            || hzqrdItemDto.getKcxje().abs().compareTo(hzqrdItemDto.getCxje().abs()) != 0
                            || hzqrdItemDto.getKcxse().abs().compareTo(hzqrdItemDto.getCxse().abs()) != 0) {
                        return Result.ERROR(ResponseEnum.HZQRD_KPYY_ERROR);
                    }
                    cxsl = hzqrdItemDto.getKcxsl().abs().negate();
                } else {
                    if (hzqrdItemDto.getKcxje().abs().compareTo(hzqrdItemDto.getCxje().abs()) != 0
                            || hzqrdItemDto.getKcxse().abs().compareTo(hzqrdItemDto.getCxse().abs()) != 0) {
                        return Result.ERROR(ResponseEnum.HZQRD_KPYY_ERROR);
                    }
                }
                cxje = hzqrdItemDto.getKcxje().abs().negate();
                cxse = hzqrdItemDto.getKcxse().abs().negate();
            } else if (CommonEnum.CHYY_02.getKey().equals(chyydm)) {
                // 商品服务编码为以3开头的冲红原因不允许选择“销售退回”
                if (invoiceItem.getSphfwssflhbbm().startsWith("3")) {
                    return Result.ERROR(ResponseEnum.HZQRD_CHYY_02_ERROR);
                }
                /*
                 * 销货退回：如蓝字发票有数量，则只允许修改冲销数量，按照单价自动计算冲销金额和冲销税额；如蓝字发票没有数量仅有金额，
                 * 则冲销数量默认为空，置灰不可修改，允许输入冲销金额，并依据税率自动计算冲销税额，其中冲销税额=蓝字发票明细行对应税率*冲销金额，
                 * 保留小数点后两位；
                 */
                if (ObjectUtil.isNotEmpty(hzqrdItemDto.getKcxsl())) {
                    cxsl = hzqrdItemDto.getCxsl().abs().negate();
                    cxje = cxsl.multiply(new BigDecimal(dj)).setScale(2, BigDecimal.ROUND_HALF_UP);
                    cxse = cxje.multiply(slv).setScale(2, BigDecimal.ROUND_HALF_UP);
                } else {
                    cxje = hzqrdItemDto.getCxje().abs().negate();
                    cxse = cxje.multiply(slv).setScale(2, BigDecimal.ROUND_HALF_UP);
                }
            } else if (CommonEnum.CHYY_03.getKey().equals(chyydm)) {
                // 商品服务编码为以 1、2 开头的冲红原因不允许选择“服务中止”
                if (invoiceItem.getSphfwssflhbbm().startsWith("1") || invoiceItem.getSphfwssflhbbm().startsWith("2")) {
                    return Result.ERROR(ResponseEnum.HZQRD_CHYY_03_ERROR);
                }
                /*
                 * 服务中止：允许输入冲销金额和冲销数量（若蓝字发票有），依据税率自动计算冲销税额，其中冲销税额=蓝字发票明细行对应税率*冲销金额，
                 * 保留小数点后两位；
                 */
                if (ObjectUtil.isNotEmpty(hzqrdItemDto.getKcxsl())) {
                    if (ObjectUtil.isEmpty(hzqrdItemDto.getCxsl())) {
                        return Result.ERROR(ResponseEnum.HZQRD_FWZZ_ERROR);
                    }
                    cxsl = hzqrdItemDto.getCxsl().abs().negate();
                    cxje = cxsl.multiply(new BigDecimal(dj)).setScale(2, BigDecimal.ROUND_HALF_UP);
                    cxse = cxje.multiply(slv).setScale(2, BigDecimal.ROUND_HALF_UP);
                } else {
                    cxje = hzqrdItemDto.getCxje().abs().negate();
                    cxse = cxje.multiply(slv).setScale(2, BigDecimal.ROUND_HALF_UP);
                }
            } else if (CommonEnum.CHYY_04.getKey().equals(chyydm)) {
                /*
                 * 销售折让：选择需折让的商品行，输入冲销金额，依据税率自动计算冲销税额，其中冲销税额=蓝字发票明细行对应税率*冲销金额
                 * 保留小数点后两位，明细的数量和单价置空
                 */
                cxje = hzqrdItemDto.getCxje().abs().negate();
                cxse = cxje.multiply(slv).setScale(2, BigDecimal.ROUND_HALF_UP);
            } else {
                return Result.ERROR(ResponseEnum.HZQRD_CHYY_ERROR);
            }

            // 不是差额征税的，进行重新计算
            if (!CommonEnum.CEZS_02.getKey().equals(cezslxdm)) {
                if (cxsl.compareTo(BigDecimal.ZERO) != 0) {
                    hzqrdItemDto.setCxsl(cxsl);
                }
                if (cxje.compareTo(BigDecimal.ZERO) == 0) {
                    return Result.ERROR("第" + num + "行明细冲销金额为0，不允许提交红字确认单申请");
                }
                hzqrdItemDto.setCxje(cxje);
                hzqrdItemDto.setCxse(cxse);
            }
            num++;
        }
        return Result.OK();
    }

    /**
     * 将DTO数据转换为红字确认单申请流程明细信息
     */
    private List<VmsApprovalHzqrdItem> convertToVmsApprovalHzqrdItem(List<VmsApprovalHzqrdItemDto> hzqrdItemDtoList, List<InvoiceItemVo> itemList) {
        List<VmsApprovalHzqrdItem> hzqrdItemList = new ArrayList<>();
        for (int i = 0; i < hzqrdItemDtoList.size(); i++) {
            VmsApprovalHzqrdItemDto hzqrdItemDto = hzqrdItemDtoList.get(i);
            Optional<InvoiceItemVo> first = itemList.stream().filter(a -> hzqrdItemDto.getId().equals(a.getId())).findFirst();
            if (first.isPresent()) {
                VmsApprovalHzqrdItem hzqrdItem = new VmsApprovalHzqrdItem();
                InvoiceItemVo invoiceItem = first.get();
                hzqrdItem.setXh((long) (i + 1));
                hzqrdItem.setLzmxxh(invoiceItem.getMxxh());
                hzqrdItem.setSphfwssflhbbm(invoiceItem.getSphfwssflhbbm());
                // 项目名称不是*开头，补全项目名称
                if (!invoiceItem.getXmmc().startsWith(CommonConstant.STRING_STAR)) {
                    // 查询明细的税收分类编码
                    LambdaQueryWrapper<VmsClassifyCode> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(VmsClassifyCode::getSphfwssflhbbm, invoiceItem.getSphfwssflhbbm());
                    queryWrapper.eq(VmsClassifyCode::getDeptCode, SecurityUtils.getDeptCode());
                    VmsClassifyCode vmsClassifyCode = vmsClassifyCodeService.getOne(queryWrapper);
                    StringBuilder stringBuilder = new StringBuilder();
                    String spmc = invoiceItem.getXmmc();
                    if (StringUtil.checkXmmc(spmc, vmsClassifyCode.getSphfwfljc())) {
                        spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(spmc).toString();
                        invoiceItem.setXmmc(spmc);
                    }
                }
                hzqrdItem.setHwhyslwfwmc(invoiceItem.getXmmc());
                // 从货物或应税劳务、服务名称中分离出商品简称和商品名称
                if (invoiceItem.getXmmc().indexOf(CommonConstant.STRING_STAR) == 0) {
                    String[] split = invoiceItem.getXmmc().split("\\*");
                    if (split.length > 2) {
                        hzqrdItem.setSpfwjc(split[1]);
                        hzqrdItem.setXmmc(invoiceItem.getXmmc().replace("*"+ split[1] + "*", ""));
                    }
                }
                hzqrdItem.setGgxh(invoiceItem.getGgxh());
                hzqrdItem.setDw(invoiceItem.getDw());
                hzqrdItem.setSl1(invoiceItem.getSlv());
                if (ObjectUtil.isNotEmpty(invoiceItem.getDj())) {
                    hzqrdItem.setFpspdj(invoiceItem.getDj());
                }

                // 从前端传来的冲销数量、冲销金额、冲销税额
                if (ObjectUtil.isNotEmpty(hzqrdItemDto.getCxsl())) {
                    hzqrdItem.setFpspsl(hzqrdItemDto.getCxsl().stripTrailingZeros().toPlainString());
                }
                hzqrdItem.setJe(hzqrdItemDto.getCxje());
                hzqrdItem.setSe(hzqrdItemDto.getCxse());

                hzqrdItemList.add(hzqrdItem);
            }
        }
        return hzqrdItemList;
    }

    /**
     * 将DTO数据转换为红字确认单申请流程信息
     */
    private VmsApprovalHzqrd convertToVmsApprovalHzqrd(VmsApprovalHzqrdDto hzqrdDto, InvoiceVo invoice) {
        VmsApprovalHzqrd hzqrd = new VmsApprovalHzqrd();
        BeanUtils.copyBeanProp(hzqrd, hzqrdDto);

        hzqrd.setApplyType(CommonEnum.HZQRD_APPROVAL_TYPE_0.getKey());
        hzqrd.setGmfmc(invoice.getGmfmc());
        hzqrd.setGmfnsrsbh(invoice.getGmfnsrsbh());
        hzqrd.setXsfmc(invoice.getXsfmc());
        hzqrd.setXsfnsrsbh(invoice.getXsfnsrsbh());
        hzqrd.setLzkprq(invoice.getKprq());
        hzqrd.setLzhjje(invoice.getHjje());
        hzqrd.setLzhjse(invoice.getHjse());
        // 蓝字发票票种代码处理
        String lzfppzdm = "";
        if (StrUtil.equalsAny(invoice.getFppz(), CommonEnum.INVOICE_TYPE_01.getKey(), CommonEnum.INVOICE_TYPE_004.getKey())) {
            lzfppzdm = CommonEnum.INVOICE_TYPE_01.getKey();
        } else if (StrUtil.equalsAny(invoice.getFppz(), CommonEnum.INVOICE_TYPE_02.getKey(),
                CommonEnum.INVOICE_TYPE_007.getKey(), CommonEnum.INVOICE_TYPE_026.getKey())) {
            lzfppzdm = CommonEnum.INVOICE_TYPE_02.getKey();
        }
        hzqrd.setLzfppzdm(lzfppzdm);
        hzqrd.setLzfptdyslxdm(invoice.getTdys());
        hzqrd.setYkjhzfpbz(CommonEnum.YKJHZFP_NO.getKey());
        hzqrd.setYxbz(CommonEnum.HZQRD_YXBZ_YES.getKey());
        hzqrd.setQydjid(SecurityUtils.getDeptCode());
        hzqrd.setCreatTime(new Date());
        hzqrd.setCreatBy(SecurityUtils.getUserCode());
        hzqrd.setUpdateTime(new Date());
        hzqrd.setUpdateBy(SecurityUtils.getUserCode());

        return hzqrd;
    }


}
